package com.tigger.common.cipher;

import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.security.InvalidAlgorithmParameterException;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;

import javax.crypto.BadPaddingException;
import javax.crypto.Cipher;
import javax.crypto.IllegalBlockSizeException;
import javax.crypto.NoSuchPaddingException;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.tigger.common.exception.AesDecipherException;
import com.tigger.common.exception.AesEncipherException;
import com.sun.org.apache.xml.internal.security.exceptions.Base64DecodingException;
import com.sun.org.apache.xml.internal.security.utils.Base64;

/**
 * Created by root on 2017/4/4.
 */
public class AesEncipher {

    final static Logger LOGGER = LoggerFactory.getLogger(AesEncipher.class);

    private final static String KEY = "XG7OSfZjInVfYAW7";
    private static final String IV_STRING = "KPUkwPNf$jmqwnK2";
    private static final String ENCRIPT_PADDING_MODE = "AES/CBC/PKCS5Padding";
    private static final String ALGORITHM = "AES";
    private static final String ENCODE_MODE = "UTF-8";

    /**
     * 对内容进行AES加密，已有秘钥
     *
     * @param content
     * @return
     * @throws AesEncipherException
     */
    public static String encipher(String content) throws AesEncipherException {
        try {
            return encipher(content, KEY);
        } catch (Exception e) {
            throw new AesEncipherException(e.getMessage());
        }
    }

    /**
     * 对内容进行AES加密
     *
     * @param content 需要加密内容
     * @param key     秘钥
     * @return
     * @throws UnsupportedEncodingException
     * @throws NoSuchPaddingException
     * @throws NoSuchAlgorithmException
     * @throws InvalidKeyException
     * @throws InvalidAlgorithmParameterException
     * @throws IllegalBlockSizeException
     * @throws BadPaddingException
     */
    public static String encipher(String content, String key) throws UnsupportedEncodingException,
            NoSuchPaddingException, NoSuchAlgorithmException, InvalidKeyException, InvalidAlgorithmParameterException,
            IllegalBlockSizeException, BadPaddingException {
        LOGGER.debug("开始AES加密，加密内容为：", content);
        byte[] contentBytes = content.getBytes(ENCODE_MODE);
        byte[] keyBytes = key.getBytes();

        // 为了能与 iOS 统一
        // 这里的 key 不可以使用 KeyGenerator、SecureRandom、SecretKey 生成
        SecretKeySpec secretKeySpec = new SecretKeySpec(keyBytes, ALGORITHM);
        byte[] initKey = IV_STRING.getBytes();

        IvParameterSpec ivParamSpec = new IvParameterSpec(initKey);

        //指定加密的算法、工作模式和填充方式
        Cipher cipher = Cipher.getInstance(ENCRIPT_PADDING_MODE);
        cipher.init(Cipher.ENCRYPT_MODE, secretKeySpec, ivParamSpec);
        byte[] encrypt = cipher.doFinal(contentBytes);

        LOGGER.debug("AES加密成功");
        return base64Encode(encrypt);
    }

    /**
     * 对AES加密的byte进行Base64加密
     *
     * @param cipherRst AES加密的byte数组
     * @return
     */
    @SuppressWarnings("restriction")
    public static String base64Encode(byte[] cipherRst) {
        LOGGER.debug("开始BASE64加密");
        return Base64.encode(cipherRst);
    }

    /**
     * AES解密，已有秘钥
     *
     * @param content
     * @return
     * @throws AesDecipherException
     * @throws IOException
     */
    public static String decipher(String content) throws AesDecipherException {
        LOGGER.debug("开始BASE64解密");
        return decipher(content, KEY);
    }

    /**
     * AES解密
     *
     * @param content 待解密内容
     * @param key     解密秘钥
     * @return
     * @throws AesDecipherException
     * @throws IOException
     */
    public static String decipher(String content, String key) throws AesDecipherException {
        try {
            LOGGER.debug("开始AES解密，待解密内容为：", content);
            byte[] encryptedBtyes = base64Decode(content);

            LOGGER.debug("BASE64解密成功");
            byte[] keyBytes = key.getBytes();

            SecretKeySpec secretKeySpec = new SecretKeySpec(keyBytes, ALGORITHM);
            byte[] initKey = IV_STRING.getBytes();

            IvParameterSpec ivParamSpec = new IvParameterSpec(initKey);

            Cipher cipher = Cipher.getInstance(ENCRIPT_PADDING_MODE);
            cipher.init(Cipher.DECRYPT_MODE, secretKeySpec, ivParamSpec);

            byte[] decrypt = cipher.doFinal(encryptedBtyes);
            String decryption = new String(decrypt, ENCODE_MODE);

            LOGGER.debug("AES解密成功");
            LOGGER.debug("decrypt string is: {}", decryption);

            return decryption;
        } catch (Exception e) {
            throw new AesDecipherException("解密失败");
        }
    }

    /**
     * Base64解密
     *
     * @param content
     * @return
     * @throws Base64DecodingException
     * @throws IOException
     */
    @SuppressWarnings("restriction")
    public static byte[] base64Decode(String content) throws Base64DecodingException {
        return Base64.decode(content);
    }

    public static void main(String[] args) {
        /**  */
        String content = "{\"token\" : \"36e4a681-5ce9-494e-a8bc-85dfcb2c472e\",\"use_type\" : \"2\",\"user_id\" : \"201705081631294154747594\",\"method\" : \"SystemService_tourist\",\"room_id\" : \"8875240\",\"room_owner_id\" : \"201705081757150680834803\"}"/*"{method:SystemService_sendmessage,token:00000000-0000-0000-0000-000000000000,telphone:18576633163}"*/;
        try {
            String e = encipher(content);
            System.out.println(e);

            String d = decipher("mdKFZCheeTe0PnQwRvqeRKCEv74FYf+CcGA4EESnfuE=");
            System.out.print(d);

        } catch (Exception e1) {
            e1.printStackTrace();
        }

    }
}
